(function($){
/*
 * Editable 1.3.4-beta
 *
 * Copyright (c) 2009 Arash Karimzadeh (arashkarimzadeh.com)
 * Licensed under the MIT (MIT-LICENSE.txt)
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Date: Mar 04 2009
 */
$.fn.editable = function(options){
	var defaults = {
		onEdit: null,
		onSubmit: null,
		onCancel: null,
		onClear: null,
		editClass: null,
		submit: null,
		cancel: null,
		result: null,
		clearBy: null,
		className: 'editable',
		guideText: 'Enter a value',
		type: 'text', //text, textarea or select
		submitBy: 'blur', //blur,change,dblclick,click
		editBy: 'click',
		options: null
	}
	if(options=='disable')
		return this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
	if(options=='enable')
		return this.bind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
	if(options=='destroy')
		return  this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable)
					.data('editable.previous',null)
					.data('editable.current',null)
					.data('editable.options',null);
	
	var options = $.extend(defaults, options);
	
	var addGuideText = function(el){
		el.addClass("guide-text").html(options.guideText);
	}
	var checkEmpty = function(el){
		if(el.text().length == 0){
			addGuideText(el);
		}
	}
	if (options.guideText){
		if (options.type=="text" || options.type=="textarea" || options.type=="time" || options.type=="date"){
			checkEmpty($(this));
		}
	}
	
	if (options.className){
		$(this).addClass(options.className);
	}
	
	options.toEditable = function(){
		$this = $(this);
		if ($this.hasClass("guide-text")){
			$this.html("").removeClass("guide-text");
		}
		$this.data('editable.current',$this.html());
		opts = $this.data('editable.options');
		
		$this.bind('keydown',function(event){
			if (event.keyCode == 13 && opts.type != "textarea"){$this.unbind('keydown');opts.toNonEditable($(this),true)}
			else if(event.keyCode == 27){$this.unbind('keydown');opts.toNonEditable($(this),false)}
		});
		
		$.editableFactory[opts.type].toEditable($this.empty(),opts);
		
		$("<div/>").addClass("options").appendTo($this);
		// Configure events,styles for changed content
		$this.data('editable.previous',$this.data('editable.current'))
			 .children()
				 .focus()
				 .addClass(opts.editClass);
		// Submit Event
		if(opts.submit){
			$('<a/>').appendTo($this.children(".options"))
						.html(opts.submit)
						.one('mousedown',function(){opts.toNonEditable($this,true)})
		}else
			$this.one(opts.submitBy,function(){opts.toNonEditable($(this),true)})
				 .children()
				 	.one(opts.submitBy,function(){opts.toNonEditable($this,true)});
		// Cancel Event
		if(opts.cancel)
			$('<a/>').appendTo($this.children(".options"))
						.html(opts.cancel)
						.one('mousedown',function(){opts.toNonEditable($this,false)});
		
		if(opts.clearBy)
			$(opts.clearBy).click(function(){
				$this.data('editable.current','');
				opts.toNonEditable($this,false);
				if (opts.onClear)
					opts.onClear();
			});
		
			
		// Call User Function
		if($.isFunction(opts.onEdit))
			opts.onEdit.apply(	$this,
									[{
										current:$this.data('editable.current'),
										previous:$this.data('editable.previous')
									}]
								);
	}
	options.toNonEditable = function($this,change){
		opts = $this.data('editable.options');
		// Configure events,styles for changed content
		$this.one(opts.editBy,opts.toEditable)
			 .data( 'editable.current',
				    change 
						?$.editableFactory[opts.type].getValue($this,opts)
						:$this.data('editable.current')
					).html(
					    opts.type=='password'
					   		?'*****'
							:$this.data('editable.current')
					).removeClass("guide-text");
		if (opts.guideText && $this.data('editable.current').length == 0){
			$this.html(opts.guideText).addClass("guide-text")
		} 
		// Call User Function
		var func = null;
		if($.isFunction(opts.onSubmit)&&change==true)
			func = opts.onSubmit;
		else if($.isFunction(opts.onCancel)&&change==false)
			func = opts.onCancel;
		if(func!=null)
			func.apply($this,
						[{
							current:$this.data('editable.current'),
							previous:$this.data('editable.previous')
						}]
					);
	}
	this.data('editable.options',options);
	return  this.one(options.editBy,options.toEditable);
}
$.editableFactory = {
	'text': {
		toEditable: function($this,options){
			$('<input/>').appendTo($this)
						 .val($this.data('editable.current'))
						 .select();
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	'password': {
		toEditable: function($this,options){
			$this.data('editable.current',$this.data('editable.password'));
			$this.data('editable.previous',$this.data('editable.password'));
			$('<input type="password"/>').appendTo($this)
										 .val($this.data('editable.current'));
		},
		getValue: function($this,options){
			$this.data('editable.password',$this.children().val());
			return $this.children().val();
		}
	},
	'textarea': {
		toEditable: function($this,options){
			$('<textarea/>').appendTo($this)
							.val($this.data('editable.current'));
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	'select': {
		toEditable: function($this,options){
			$select = $('<select/>').appendTo($this);
			$.each( options.options,
					function(key,value){
						$('<option/>').appendTo($select)
									.html(value)
									.attr('value',key);
					}
				   )
			$select.children().each(
				function(){
					var opt = $(this);
					if(opt.text()==$this.data('editable.current'))
						return opt.attr('selected', 'selected').text();
				}
			)
		},
		getValue: function($this,options){
			var item = null;
			$('select', $this).children().each(
				function(){
					if($(this).attr('selected'))
						return item = $(this).text();
				}
			)
			return item;
		}
	},
	'time': {
		toEditable: function($this,option){
			var hour = $("<select/>").addClass("hour");
			var minute = $("<select/>").addClass("minute");
			// FIX ME - eq(0) eq(1) doesn't allow for future changes
			var currentHour = $($this.data('editable.current')).eq(0).text();
			var currentMinute = $($this.data('editable.current')).eq(2).text();
			for (var i=0; i<24; i++){
				var hourOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(hour);
				if (currentHour == i){
					hourOption.attr("selected","selected");
				}
			}
			for (var i=0; i<60; i=i+5){
				var minuteOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(minute);
				if (currentMinute == i){
					minuteOption.attr("selected","selected");
				}
			}
			$this.append(hour,minute);
		},
		getValue: function($this,options){
			return $this.find(".hour").val() + $this.find(".minute").val(); 
		}
	},
	'date': {
		toEditable: function($this,option){
			var day = $("<select/>").addClass("day");
			var month = $("<select/>").addClass("month");
			var year = $("<select/>").addClass("year");
			var currentData = IODateTime.fromNiceDateToIODate($this.data('editable.current'));
			var currentDay = currentData.day;
			var currentMonth = currentData.month;
			var currentYear = currentData.year;
			for (var i=1; i<=31; i++){
				var dayOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(day);
				if (currentDay == i){
					dayOption.attr("selected","selected");
				}
			}
			for (var i=0; i<IODateTime.months.length; i++){
				var monthOption = $("<option value=" + i + "/>").html(IODateTime.months[i]).appendTo(month);
				if (currentMonth == i){
					monthOption.attr("selected","selected");
				}
			}
			var thisYear = new Date().getFullYear();
			for (var i=thisYear; i<=thisYear+1; i++){
				var yearOption = $("<option/>").html(i).appendTo(year);
				if (currentYear == i){
					yearOption.attr("selected","selected");
				}
			}
			$this.append(day,month,year);
		},
		getValue: function($this,options){
			var d = new Date();
			d.setFullYear(parseInt($this.find(".year").val(), 10), parseInt($this.find(".month").val(), 10), parseInt($this.find(".day").val(), 10));
			return IODateTime.toNiceDate(d); 
		}
	}
}
})(jQuery);